# !/usr/bin/python
# -*- coding: utf-8 -*-

# mediaplex
# multimedia platform
#
# this file is licensed under the MIT license
# read "LICENSE.MIT" in the root of this distribution

__authors__ = 'Jan Jokela <janjokela@gmail.com>'
__description__ = 'Media library'

import os
import mmpython
import mediaplex.core.conf.log as log

class Generic:
    def __init__(self, storage_backend='sqlite', database_name='mediadb',
                 host='127.0.0.1', username='username', password='password'):
        """ Initializes the class procedures.

        Creates an storage object to interface with. It will use it
        to store and retrieve relevant information about the media
        that the database is aware of.
        """
        storage_backends = {
            'sqlite':drivers.SQLite,
        }
        # If the database doesn't exist we must rebuild the storage system
        if not os.path.exists(database_name):
            self.storage_backend._rebuild_storage_system()
        # Lets connect to the database
        self.storage_backend = storage_backends[storage_backend](database_name, host, username, password)
        log.info('core.library', 'Loaded library interface. backend: ' + str(storage_backend))

    def add_media(self, media_object):
        """ Adds a media object to the library.

        :media_object (media.object.*) -- The object representing the media.
        """
        return self.storage_backend.add_record(media_object.media_type, media_object)

    def rem_media(self, media_object):
        """ Removes a file from the library.

        :media_object (media.object.*) -- The object representing the media.
        """
        return self.storage_backend.rem_record(media_object.media_type,
                                              'uri',
                                              media_object.uri)

    def change_media(self, old_media_object, new_media_object):
        """ Alters an already present record.

        This method should be called whenever an already existing
        record has its information altered.

        :old_media_object (media.object.*) -- Object representing the old media.
        :new_media_object (media.object.*) -- Object containing newer info.

        """
        return self.storage_backend.change_record(old_media_object.media_type,
                                                 old_media_object,
                                                 new_media_object)

    def get_media_files(self, media_type, fields_list=['title']):
        """ Returns a list of objects.

        Regarding the criteria specified (which matches the sorting
        ones - ex: name, artist, album, genre, year), it returns a
        list containing the files that match it.

        :media_type (string) -- The type of media to be looked for.
        :fields_list (list) -- The criteria that must be matched.

        """
        self.results = []
        i =1
        for row in self.storage_backend.get_records(media_type, fields_list):
            self.results.append(mappings.classes[media_type](**row))
            i += 1
        return self.results
    
    def add_path(self, search_path, filter=('audio', 'video', 'image')):
        """ Adds media objects in given path to the library.
        
        :search_path (string) -- path to search for media files
        :filter (list) -- specify what mime types to search for
        """
        
        for root, directory, files_list in os.walk(search_path):
            # This prevents the case in which the media is on a root directory
            if len(directory) <= 0:
                directory = ''
            else:
                directory = os.path.join(*directory)         
            # Get the current files' path
            path = os.path.join(root, directory)
            for item in files_list:
                file_path = os.path.join(path, item)
                # Check first if we can gather any information about the file
                metadata = mmpython.parse(file_path)
                if metadata:
                    # Get part of the declared mime type
                    mime_type = metadata.mime.split('/')[0]
                    # Check if our mime type is in the filter
                    if mime_type in filter:
                        # Instantiate the correct class based on mime type
                        media_object = mappings.classes[mime_type](file_path)
                        #print media_object
                        # Make sure the media object's metadata is up to date    
                        media_object.update_metadata(metadata)
                        # And, finally, add the information to the database
                        try:
                            self.add_media(media_object)
                        except: pass
                        
    def rem_path(self, search_path, filter=('audio', 'video', 'image')):
        """ Removes media objects from the library belonging to the given path.
        
        :search_path (string) -- path that contains media files to be removed
        :filter (list) -- is used to specify what mime types to search for
        """
        
        # for each mime type in our filter
        for mime_type in filter:
            # lets get a list of media objects with the uri (filesystem url) field
            media_objects = self.get_media_files(mime_type, ['uri'])
            # now for each media object
            for media_object in media_objects:
                # lets scan through all our files and folder in the search path
                for root, directory, files_list in os.walk(search_path):
                    # This prevents the case in which the media is on a root directory
                    if len(directory) <= 0:
                        directory = ''
                    else:
                        directory = os.path.join(*directory)         
                    # Get the current files' path
                    path = os.path.join(root, directory)
                    for item in files_list:
                        # lets get the file path and encode it in unicode
                        # we know odd filenames exist
                        file_path = unicode(os.path.join(path, item), "utf-8")   
                        file_path.encode("utf-8")
                        # lets also encode the uri in unicode
                        uri = unicode(media_object.uri)
                        uri.encode("utf-8")
                        # if they are equal this means that we want to delete the current media_object
                        if file_path == uri:
                            self.rem_media(media_object)
